package com.future.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.future.allUtils.constants.CodeConstants;
import com.future.allUtils.enums.RoleEnum;
import com.future.allUtils.utils.CacheClient;
import com.future.domain.Follow;
import com.future.domain.User;
import com.future.domain.DTO.UserDTO;
import com.future.exception.BusinessException;
import com.future.mapper.FollowMapper;
import com.future.mapper.UserMapper;
import com.future.service.FollowService;
import io.swagger.models.auth.In;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 关注服务实现类
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements FollowService {

    private static final Logger logger = LoggerFactory.getLogger(FollowServiceImpl.class);
    // 关注列表缓存键前缀：key = FOLLOWING_LIST_KEY + 用户ID
    public static final String FOLLOWING_LIST_KEY = "follow:list:following:";
    // 粉丝列表缓存键前缀：key = FOLLOWER_LIST_KEY + 用户ID
    public static final String FOLLOWER_LIST_KEY = "follow:list:follower:";

    // 列表缓存过期时间（可根据业务调整，此处设30分钟+随机值防雪崩）
    public static final Long FOLLOW_LIST_CACHE_TTL = 30L;
    public static final TimeUnit FOLLOW_LIST_CACHE_TIME_UNIT = TimeUnit.MINUTES;


    @Autowired
    private FollowMapper followMapper;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CacheClient cacheClient;
    /**
     * 关注用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean followUser(Long userId, Long followedUserId) {
        // 参数校验
        if (userId == null || followedUserId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        if (userId.equals(followedUserId)) {
            throw new BusinessException(CodeConstants.PROJECT_OPERATION_CONFLICT, "不能关注自己");
        }

        // 检查用户是否存在
        User user = userMapper.selectById(followedUserId);
        if (user == null) {
            throw new BusinessException(CodeConstants.PROJECT_DATA_NOT_FOUND, "关注的用户不存在");
        }

        // 检查是否已关注
        if (isFollowing(userId, followedUserId)) {
            throw new BusinessException(CodeConstants.PROJECT_DATA_DUPLICATE, "已经关注该用户");
        }

        try {
            // 创建关注记录
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowedUserId(followedUserId);
            follow.setCreatedAt(LocalDateTime.now());


            // 缓存更新策略
            String userFollowingKey = FOLLOWING_LIST_KEY + userId;
            String followedFollowerKey = FOLLOWER_LIST_KEY + followedUserId;
            cacheClient.deleteByPattern(userFollowingKey); // 删除操作用户的关注列表缓存
            cacheClient.deleteByPattern(followedFollowerKey); // 删除被关注用户的粉丝列表缓存
            return save(follow);
        } catch (Exception e) {
            logger.error("关注用户失败: userId={}, followedUserId={}", userId, followedUserId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "关注用户失败");
        }
    }

    /**
     * 取消关注
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unfollowUser(Long userId, Long followedUserId) {
        // 参数校验
        if (userId == null || followedUserId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        // 检查是否已关注
        if (!isFollowing(userId, followedUserId)) {
            throw new BusinessException(CodeConstants.PROJECT_STATE_CONFLICT, "未关注该用户");
        }

        try {

            // 缓存更新策略
            String userFollowingKey = FOLLOWING_LIST_KEY + userId;
            String followedFollowerKey = FOLLOWER_LIST_KEY + followedUserId;
            cacheClient.deleteByPattern(userFollowingKey); // 删除操作用户的关注列表缓存
            cacheClient.deleteByPattern(followedFollowerKey); // 删除被关注用户的粉丝列表缓存

            // 删除关注记录
            return remove(
                    new QueryWrapper<Follow>()
                            .eq("user_id", userId)
                            .eq("followed_user_id", followedUserId)
            );
        } catch (Exception e) {
            logger.error("取消关注失败: userId={}, followedUserId={}", userId, followedUserId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "取消关注失败");
        }
    }

    /**
     * 检查是否已关注
     */
    @Override
    public boolean isFollowing(Long userId, Long followedUserId) {
        // 参数校验
        if (userId == null || followedUserId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        try {
            Integer count = followMapper.checkFollow(userId, followedUserId);
            return count != null && count > 0;
        } catch (Exception e) {
            logger.error("检查关注状态失败: userId={}, followedUserId={}", userId, followedUserId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "检查关注状态失败");
        }
    }

    /**
     * 获取用户的关注列表
     */
    @Override
    public List<UserDTO> getFollowingList(Long userId, Integer pageNum, Integer pageSize) {
        // 参数校验
        if (userId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        try {
            Page<Long> page = new Page<>(pageNum, pageSize);
            List<Long> followingIds = followMapper.getFollowingList(page,userId);
            return convertToUserDTOList(followingIds);
        } catch (Exception e) {
            logger.error("获取关注列表失败: userId={}", userId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "获取关注列表失败");
        }
    }

    /**
     * 获取用户的粉丝列表
     */
    @Override
    public List<UserDTO> getFollowerList(Long userId,Integer pageNum, Integer pageSize) {
        // 参数校验
        if (userId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        try {
            Page<Long> page=new Page<>(pageNum, pageSize);
            List<Long> followerIds = followMapper.getFollowerList(page,userId);
            return convertToUserDTOList(followerIds);
        } catch (Exception e) {
            logger.error("获取粉丝列表失败: userId={}", userId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "获取粉丝列表失败");
        }
    }

    /**
     * 获取用户的关注数量
     */
    @Override
    public Long getFollowingCount(Long userId) {
        // 参数校验
        if (userId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        try {
            return followMapper.getFollowingCount(userId);
        } catch (Exception e) {
            logger.error("获取关注数量失败: userId={}", userId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "获取关注数量失败");
        }
    }

    /**
     * 获取用户的粉丝数量
     */
    @Override
    public Long getFollowerCount(Long userId) {
        // 参数校验
        if (userId == null) {
            throw new BusinessException(CodeConstants.PROJECT_VALIDATE_ERROR, "用户ID不能为空");
        }

        try {
            return followMapper.getFollowerCount(userId);
        } catch (Exception e) {
            logger.error("获取粉丝数量失败: userId={}", userId, e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "获取粉丝数量失败");
        }
    }

    /**
     * 将用户ID列表转换为UserDTO列表
     */
    private List<UserDTO> convertToUserDTOList(List<Long> userIds) {
        List<UserDTO> userDTOList = new ArrayList<>();
        if (userIds == null || userIds.isEmpty()) {
            return userDTOList;
        }

        try {
            for (Long id : userIds) {
                // 1. 校验用户ID非空
                if (id == null) {
                    logger.warn("用户ID为空，跳过处理");
                    continue;
                }

                // 2. 查询用户信息，校验非空
                User user = userMapper.selectById(id);
                if (user == null) {
                    logger.warn("用户不存在，userId={}", id);
                    continue;
                }

                // 3. 转换为DTO
                UserDTO userDTO = new UserDTO();
                BeanUtils.copyProperties(user, userDTO);

                // 4. 处理角色列表（非空判断）
                List<Integer> roles = userMapper.getUserRole(id);
                if (roles != null) {
                    List<String> roleNames = roles.stream()
                            .map(roleId -> {
                                // 4.1 校验roleId非空
                                if (roleId == null) {
                                    logger.warn("用户角色ID为空，userId={}", id);
                                    return "未知角色";
                                }
                                // 4.2 校验枚举存在性
                                RoleEnum roleEnum = RoleEnum.getByRoleId(roleId);
                                if (roleEnum == null) {
                                    logger.warn("未定义的角色ID: roleId={}, userId={}", roleId, id);
                                    return "未知角色"; // 用默认值避免空指针
                                }
                                return roleEnum.getRoleName();
                            })
                            .collect(Collectors.toList());
                    userDTO.setRoles(roleNames);
                } else {
                    userDTO.setRoles(new ArrayList<>());
                    logger.info("用户无角色信息，userId={}", id);
                }
                userDTO.setIdStr(user.getId().toString());
                userDTOList.add(userDTO);
            }
        } catch (Exception e) {
            logger.error("转换用户列表失败", e);
            throw new BusinessException(CodeConstants.SYSTEM_DB_ERROR, "转换用户列表失败");
        }

        return userDTOList;
    }
}